#include <sys/types.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <thread>

#define WRITE_CNT 1000

void write_to_epoll_dev(int fd)
{
    for (int i = 0; i < WRITE_CNT; i++)
    {
        int ret = write(fd, &i, sizeof(i));
        assert(ret > 0);
    }
}

int main(void)
{
    int fd = open("/dev/epoll_demo", O_RDWR);

    if (-1 != fd)
    {
        struct epoll_event ev_globalfifo;
        int err;

        int epfd = epoll_create(1);
        if (epfd < 0)
        {
            perror("epoll_create(1)");
            return -1;
        }

        bzero(&ev_globalfifo, sizeof(struct epoll_event));
        ev_globalfifo.data.fd = fd;
        ev_globalfifo.events = EPOLLIN;
        err = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev_globalfifo);
        if (err < 0)
        {
            perror("epoll_ctl()");
            return -1;
        }

        std::thread t0(write_to_epoll_dev, fd);

        int readcnt = 0;
        while (1)
        {
            err = epoll_wait(epfd, &ev_globalfifo, 1, -1);
            if (err < 0)
            {
                perror("epoll_wait()");
            }
            else
            {
                assert((ev_globalfifo.events & EPOLLIN) != 0);
                readcnt++;

                int temp;
                int readbytes = read(fd, &temp, sizeof(temp));
                assert(readbytes > 0);

                if (readcnt == WRITE_CNT)
                {
                    break;
                }
            }
        }

        //this time should timeout
        err = epoll_wait(epfd, &ev_globalfifo, 1, 5000);
        assert(0 == err);

        err = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev_globalfifo);
        if (err < 0)
        {
            perror("epoll_ctl()");
        }

        t0.join();

        close(fd);
    }
}